/*
 * HttpConn.cpp
 *
 *   Created on: 2010-2-11     
 *  Description: 
 *    Copyright: 2010 @ ICT Li Heyuan
 */

#include "../../include/conn/HttpConn.h"
#include "../../include/server/Server.h"
#include "../../include/server/TcpServer.h"
#include "../../include/net/EasyAddr.h"
#include "../../include/util/Util.h"
#include "../../include/thread/JobPoll.h"

#include <iostream>
#include <cstdlib>
#include <sstream>
using std::cout;
using std::cerr;
using std::ostringstream;

//HTTP代码对应的消息
string HttpConn::HTTP_MSG_200("OK");
string HttpConn::HTTP_MSG_400("Bad Request");
string HttpConn::HTTP_MSG_500("Internal Server Error");

HttpConn::HttpConn(Server* server, int sock, const EasyAddr &addr) :
	Conn(server, sock, addr), _stage(STAGE_READ), _nSendLeft(0)
{
}

HttpConn::~HttpConn()
{
}

bool HttpConn::handle(unsigned int event)
{
	bool ret = true;
	switch (event)
	{

	//read ready
	case TcpServer::EPOLL_IN:
	{
		if (_stage == STAGE_READ || _stage == STAGE_READ_HEAD
				|| STAGE_READ_CONTENT)
		{
			ret = handle_read();
		}
		else
		{
			//不再读阶段如果eof了，就false,不继续监视
			ret = !isEOF();
		}
	}//EPOLL_IN
		break;

		//Method执行完毕，callback
	case JobPoll::FINISH:
	{
		handle_execute_finish();
		//模拟EPOLL_OUT发生了
		ret = handle(TcpServer::EPOLL_OUT);
	}//Method执行完毕后的callback
		break;

		//write ready
	case TcpServer::EPOLL_OUT:
	{
		if (_stage == STAGE_WRITE)
		{
			ret = handle_write();
		}
		else if (_stage == STAGE_FINISH)
		{
			//如果已经结束，不需要再写入了
			ret = false;
		}
	}//EPOLL_OUT
		break;
	}//switch

	return ret;
}

bool HttpConn::handle_read()
{
	bool eof = false;
	if (!Network::recvBytes(_sock, _rcvBuf, eof))
	{
		_server->getNetLogger().error("fd=%d %s:%d recv() error : %s", _sock,
				_addr.ip.c_str(), _addr.port,
				Util::getInstance()->getErrMsg().c_str());
		return false;
	}//recv fail
	else
	{
		if (eof)
		{
			//sock已经关闭
			return false;
		}//eof
		else
		{
			//sock没有关闭，根据状态机判断
			if (_stage == STAGE_READ)
			{
				//尝试找到CONTENT_LENGTH
				unsigned long len = find_Content_Length();
				if (len)
				{
					//定位了Length
					_stage = STAGE_READ_HEAD;
					_contentLen = len;
					_server->getJsonRpcLogger().info(
							"fd=%d %s:%d parser Content-Length from HTTP-HEAD %ld",
							_sock, _addr.ip.c_str(), _addr.port, _contentLen);
				}
				else
				{
					//没有定位Length，补充判断是否已经通过了DATA区域
					string::size_type start = find_Data_Start();
					if (start != string::npos)
					{
						//没有Content-Length，返回400
						handle_http_error(HTTP_400, HTTP_MSG_400,
								"Please use POST to send json request.");
						_server->getJsonRpcLogger().error(
								"fd=%d %s:%d fail get Content-Length from HTTP-HEAD.\n%s",
								_sock, _addr.ip.c_str(), _addr.port,
								Util::replaceLine(_rcvBuf).c_str());
						return true;
					}
				}
			}//STAGE_READ

			if (_stage == STAGE_READ_HEAD)
			{
				//尝试定位、切断POST DATA开始的地方
				string::size_type start = find_Data_Start();
				if (start != string::npos)
				{
					//如果找到了DATA开始的区
					_rcvBuf.erase(0, start + 4);
					_stage = STAGE_READ_CONTENT;
				}
			}

			if (_stage == STAGE_READ_CONTENT)
			{
				if (_rcvBuf.size() >= _contentLen)
				{
					//已经获取了全部的request请求，截取，交给json_cpp解析
					_rcvBuf.erase(_contentLen, _rcvBuf.size() - _contentLen);
					//cout << _rcvBuf << endl;
					try
					{
						//解析失败/null/不是对象都算作失败
						if (!_jsonReader.parse(_rcvBuf, _jsonReq) || _jsonReq
								== Json::nullValue || !_jsonReq.isObject())
						{
							throw "";
						}
					} catch (...)
					{
						//Log 获得的完整DATA不是json-rpc请求
						_server->getJsonRpcLogger().error(
								"fd=%d %s:%d post data is not json-rpc request.\n%s",
								_sock, _addr.ip.c_str(), _addr.port,
								Util::replaceLine(_rcvBuf).c_str());
						//解析失败
						handle_http_error(HTTP_400, HTTP_MSG_400,
								"post data is not json-rpc request");
						return true;
					}
					//解析成功
					_server->getJsonRpcLogger().info(
							"fd=%d %s:%d get json-rpc request.\n%s", _sock,
							_addr.ip.c_str(), _addr.port, Util::replaceLine(
									_rcvBuf).c_str());
					_stage = STAGE_EXECUTE;
					_rcvBuf.clear();
					//在JobPoll中执行Method
					handle_execute();
				}//end 获取了全部request
				return true;
			}//STAGE_READ_CONTENT

			return true;
		}//!eof
	}//recv success
}

bool HttpConn::handle_write()
{
	//notification直接结束
	if (_isNotification)
	{
		//notification需要Server主动关闭
		return false;
	}

	if (!_nSendLeft)
	{
		//记录写入完毕
		_server->getNetLogger().info("fd=%d %s:%d send() %ld bytes finish ",
				_sock, _addr.ip.c_str(), _addr.port, _sendBuf.size());
		if (_server->isCloseFirst())
		{
			//Server主动先关闭
			return false;
		}
		else
		{
			//等着Client关闭先
			return true;
		}
	}

	//把数据写出，直到完毕
	if (!Network::sendBytes(_sock, _sendBuf, _nSendLeft))
	{
		//写失败
		_server->getNetLogger().error("fd=%d %s:%d send() fail : %s ", _sock,
				_addr.ip.c_str(), _addr.port,
				Util::getInstance()->getErrMsg().c_str());
		return false;
	}//send fail
	else
	{
		if (_nSendLeft == 0)
		{
			//全写入完毕，让client关闭
			//记录写入完毕
			_server->getNetLogger().info(
					"fd=%d %s:%d send() %ld bytes finish ", _sock,
					_addr.ip.c_str(), _addr.port, _sendBuf.size());
			_sendBuf.clear();

			//判断是否需要主动关闭
			if (_server->isCloseFirst())
			{
				return false;
			}
			else
			{
				return true;
			}
		}
		else
		{
			return true;
		}
	}//send success
}

void HttpConn::handle_execute()
{
	//加入JobPoll异步等待执行
	JobPoll::getInstance()->addJob(this);
}

void HttpConn::handle_execute_finish()
{
	//json->string & 状态转换
	string resp = _jsonWriter.write(_jsonResp);
	_sendBuf = make_http_resp(HTTP_OK, HTTP_MSG_200, resp);
	_nSendLeft = _sendBuf.size();

	//决定是否回写response
	if (_jsonReq["id"] != Json::nullValue)
	{
		//id!=null,call需要回写
		_stage = STAGE_WRITE;

		//记录call的逻辑执行以及结果
		if (_exeSuccess)
		{
			//call成功
			_server->getJsonRpcLogger().info(
					"fd=%d %s:%d execute method(call) success \n%s", _sock,
					_addr.ip.c_str(), _addr.port,
					Util::replaceLine(_sendBuf).c_str());
		}
		else
		{
			//call失败
			_server->getJsonRpcLogger().error(
					"fd=%d %s:%d execute method(call) fail : %s \n%s", _sock,
					_addr.ip.c_str(), _addr.port, _exeError.c_str(),
					Util::replaceLine(_sendBuf).c_str());
		}
	}
	else
	{
		_isNotification = true;
		//id==null,notification直接结束连接
		_stage = STAGE_FINISH;

		//记录notification的逻辑执行以及结果
		if (_exeSuccess)
		{
			//notification成功
			_server->getJsonRpcLogger().info(
					"fd=%d %s:%d execute method(notification) success ", _sock,
					_addr.ip.c_str(), _addr.port);
		}
		else
		{
			//notification失败
			_server->getJsonRpcLogger().error(
					"fd=%d %s:%d execute method(notification) fail : %s ",
					_sock, _addr.ip.c_str(), _addr.port, _exeError.c_str());
		}
	}
}

unsigned long HttpConn::find_Content_Length()
{
	//尝试找Content-Length
	string::size_type pos1 = _rcvBuf.find("Content-Length");
	if (pos1 != string::npos)
	{
		//找到了Content-Length，尝试找\r\n
		string::size_type pos2 = _rcvBuf.find("\r\n", pos1);

		if (pos2 != string::npos)
		{
			//找到了Content-Length和\r\n，分离len的数值
			pos1 += 16;
			string lenStr = _rcvBuf.substr(pos1, pos2 - pos1);
			unsigned long len = ::atol(lenStr.c_str());
			return len;
		}
	}// if ! npos

	return 0;
}

string::size_type HttpConn::find_Data_Start()
{
	return _rcvBuf.find("\r\n\r\n");
}

void HttpConn::handle_http_error(unsigned int code, const string &msg,
		const string &data)
{
	//获得错误的http response
	_sendBuf = make_http_resp(code, msg, data);
	_nSendLeft = _sendBuf.size();

	/*	cout << _sendBuf << endl;*/

	_stage = STAGE_WRITE;
}

string HttpConn::make_http_resp(unsigned int code, const string &msg,
		const string & data)
{
	ostringstream ss;

	ss << "HTTP/1.1 " << code << " " << msg << "\r\n";
	ss << "Content-Length: " << data.size() << "\r\n";
	ss << "Content-Type: " << "text/plain" << "\r\n\r\n";
	//ss << "Server: Json-Rpc-Server" << "\r\n";
	//ss << "Date: Fri, 12 Feb 2010 05:28:22 GMT\r\n\r\n";
	//ss << "Connection: close" << "\r\n\r\n";
	ss << data;

	return ss.str();
}
